#pragma once
#include <string>
#include <poll.h>
#include "Dispatcher.hpp"
#include "EventLoop.hpp"
#include "Channel.hpp"
using namespace std;

class PollDispatcher : public Dispatcher
{
public:
    // 初始化epoll,select,poll函数对应的数据块
    PollDispatcher(EventLoop *evloop)
        : Dispatcher(evloop)
    {
        m_maxfd = 0;
        m_fds = new struct pollfd[m_maxNode];
        for (int i = 0; i < m_maxNode; ++i)
        {
            m_fds[i].fd = -1;
            m_fds[i].events = 0;
            m_fds[i].revents = 0;
        }
        m_name = "Poll";
    }
    // 实现多态需要将析构函数设置为虚函数
    // 将下面的函数设置为虚函数后，子类就能对父类函数进行重写操作
    // 添加
    ~PollDispatcher()
    {
        delete[] m_fds;
    }
    // 表示该函数是从父类继承的虚函数
    int add() override
    {
        int events = 0;                                      // channel中的events与ev联合体中的events是不一样的
        if (m_channel->getEvent() & (int)FDEvent::ReadEvent) // channel中是我们自己定义的，而ev中对应的是epollin，epollout，
                                                             // 额外定义一个events变量，然后通过判断channel中的读写事件，对events变量按位与
        {                                                    // 最后将events变量赋给ev联合体中的成员events
            events |= POLLIN;
        }
        if (m_channel->getEvent() & (int)FDEvent::WriteEvent)
        {
            events |= POLLOUT;
        }
        int i = 0;
        for (; i < m_maxNode; ++i)
        {
            if (m_fds[i].fd == -1)
            {
                m_fds[i].events = events;
                m_fds[i].fd = m_channel->getSocket();
                m_maxfd = i > m_maxfd ? i : m_maxfd;
                break;
            }
        }
        if (i >= m_maxNode)
        {
            return -1;
        }
        return 0;
    }
    // 删除
    int remove() override
    {
        int i = 0;
        for (; i < m_maxNode; ++i)
        {
            if (m_fds[i].fd == m_channel->getSocket())
            {
                m_fds[i].events = 0;
                m_fds[i].revents = 0;
                m_fds[i].fd = -1; // 无效文件描述符
                break;
            }
        }
        // 通过channel释放对应的TcpConnection资源
        // channel属于某一个TcpConnection，channel中封装了一个fd,通过结构体成员访问外部实例需要将外部实例传递给内部的成员
        m_channel->destoryCallback(const_cast<void *>(m_channel->getArg()));
        if (i >= m_maxNode)
        {
            return -1;
        }
        return 0;
    }
    // 修改
    int modify() override
    {
        int events = 0;                                      // channel中的events与ev联合体中的events是不一样的
        if (m_channel->getEvent() & (int)FDEvent::ReadEvent) // channel中是我们自己定义的，而ev中对应的是epollin，epollout，
                                                             // 额外定义一个events变量，然后通过判断channel中的读写事件，对events变量按位与
        {                                                    // 最后将events变量赋给ev联合体中的成员events
            events |= POLLIN;
        }
        if (m_channel->getEvent() & (int)FDEvent::WriteEvent)
        {
            events |= POLLOUT;
        }
        int i = 0;
        for (; i < m_maxNode; ++i)
        {
            if (m_fds[i].fd == m_channel->getSocket())
            {
                m_fds[i].events = events;
                break;
            }
        }
        if (i >= m_maxNode)
        {
            return -1;
        }
        return 0;
    }
    // 事件检测
    int dispatch(int timeout = 2) override
    {
        int count = poll(m_fds, m_maxfd + 1, timeout * 1000);
        if (count == -1)
        {
            perror("poll");
            exit(0);
        }
        for (int i = 0; i < m_maxfd; ++i)
        {
            // 依次取出有效数组的文件描述符并保存
            if (m_fds[i].fd == -1)
            {
                continue;
            }

            if (m_fds[i].revents & POLLIN)
            {
                m_evLoop->eventActivate(m_fds[i].fd, (int)FDEvent::ReadEvent);
            }
            if (m_fds[i].revents & POLLOUT)
            {
                m_evLoop->eventActivate(m_fds[i].fd, (int)FDEvent::WriteEvent);
            }
        }
        return 0;
    }

private:
    int m_maxfd;
    struct pollfd *m_fds;
    // struct pollfd m_fds[1024];
    const int m_maxNode = 1024;
};